package com.example.emos.api.business.service.impl;

import cn.hutool.core.lang.UUID;
import com.example.emos.api.business.service.FileService;
import com.example.emos.api.common.R;
import com.example.emos.api.common.exception.EmosException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class FileServiceImpl implements FileService {

    @Autowired
    @Lazy
    private FileService fileService;

    @Override
    public R uploadFile(MultipartFile file, String fileName, String fileMD5, Integer chunkIndex, Integer chunks) {

        //将分片文件上传到临时目录
        File fileFolder = null;
        try {
            String tempFolder = System.getProperty("java.io.tmpdir");
            fileFolder = new File(tempFolder + File.separator + fileMD5);
            if (!fileFolder.exists()) {
                fileFolder.mkdirs();
            }
            File newFile = new File(fileFolder.getPath() + File.separator + chunkIndex);
            FileUtils.copyInputStreamToFile(file.getInputStream(), newFile);
            //
            if (chunkIndex < chunks - 1) {
                return R.ok();
            }

            //如果有事务则将分片转换加入到里面
            /*TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {

                }
            });*/
            //如果是最后一个分片,则将临时的目录的分片文件进行异步合并
            fileService.transferTo(fileMD5);

            //

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileFolder != null) {
                fileFolder.delete();
            }
        }
        return null;
    }

    public void transferTo(String fileMD5) throws IOException {

        String tempFolderName = System.getProperty("java.io.tmpdir") + File.separator + fileMD5;
        File fileFolder = new File(tempFolderName);

        //生成到目标文件目录
        File tarFolder = new File("D:" + File.separator + UUID.randomUUID());
        if (!tarFolder.exists()) {
            tarFolder.mkdirs();
        }

        String realFileName = "fileName" + ".mp4";
        String targetFilePath = tarFolder.getPath() + File.separator + realFileName;
        union(fileFolder.getPath(), targetFilePath, realFileName, true);

    }

    /**
     * 文件合并逻辑
     *
     * @param dirPath:临时目录
     * @param toFilePath：将文件合并该路径下
     * @param fileName：文件名
     * @param delSource：是否删除源文件
     */
    private void union(String dirPath, String toFilePath, String fileName, Boolean delSource) throws IOException {
        File dir = new File(dirPath);
        if (!dir.exists()) {
            throw new EmosException("异常了");
        }
        File[] fileList = dir.listFiles();
        File targetFile = new File(toFilePath);
        targetFile.createNewFile();
        RandomAccessFile writeFile = null;
        try {
            writeFile = new RandomAccessFile(targetFile, "rw");
            byte[] b = new byte[1024];
            for (File file : fileList) {
                int len = -1;
                RandomAccessFile accessFile = new RandomAccessFile(file, "r");
                while ((len = accessFile.read(b)) != -1) {
                    writeFile.write(b, 0, len);
                }
                accessFile.close();
            }
        } catch (Exception e) {
            log.error(fileName + "文件合并失败");
        } finally {
            try {
                if (writeFile != null) {
                    writeFile.close();
                }
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        }
    }
}
